#ifndef TIMER_LOG_H
#define TIMER_LOG_H

#include <stdlib.h>
#include <stdio.h>
#include <timer.h>
#include <sys/types.h>
#include <string.h>
// #include <cstdint>
#include <pthread.h>
#include <signal.h>
#include "socket.h"
#include "nccl.h"
#include "core.h"

enum timer_log_type{
  NCCL_LOG_NOT_USE = 0,
  NCCL_LOG_TELEMETRY = 1,
  NCCL_LOG_HANG = 2
};

struct timer_log{
  uint8_t srcIp[4];
  uint8_t dscIp[4];
  struct timespec send_start;
  struct timespec send_end;  
  int loged_start;
  int loged_end;
  unsigned long long diff;
  int size = 0;
  double rate;
  std::string NetworkCardName;
};

enum linkStatus{
  LINK_STATUS_UNUSED,
  LINK_STATUS_USED,
  LINK_STATUS_WAIT,
  LINK_STATUS_SUCCESS,
  LINK_STATUS_WRONG,
  LINK_STATUS_WRONG_WAIT
};

struct linkStatusTest{
  int status;
  struct ibv_qp *linkPingQp;
  struct timespec send_start;
  struct timespec send_end;
  int events;
};


struct timer_log_res{
  uint8_t srcIp[4];
  uint8_t dscIp[4];
  unsigned long long send_start_sec;
  unsigned long long send_end_sec;
  unsigned long long diff;//nsec
  int size = 0;
};

#define TIMER_LOG_ENTRY           0
#define TIMER_LOG_NCCL_HANG       0
#define TIMER_LOG_NCCL_TELEMETRY  0


#define TIMER_LOG_QUEUE_READ -1
#define TIMER_LOG_QUEUE_WRITE 1


#define TIMER_LOG_MAX_LEN 1000
struct timer_log_queue{
  pthread_t thread;
  pthread_mutex_t lock;
  volatile int state;
  volatile int stop;
  struct timer_log log[TIMER_LOG_MAX_LEN + 10];
  struct timer_log_res t_res[TIMER_LOG_MAX_LEN + 10];
  volatile int cnt;
  volatile int idx;
  volatile bool collect;

  void push(struct timer_log _log){
    log[idx] = _log;
    if(cnt < TIMER_LOG_MAX_LEN) cnt++;
    idx = (idx + 1) % TIMER_LOG_MAX_LEN;
  }
  struct timer_log pop(){
    // struct timer_log res;
    // return res;
    if(!cnt){
        struct timer_log res;
        memset((void *)&res, 0, sizeof(res));
        return res;
    }
    cnt--;
    idx+=TIMER_LOG_MAX_LEN-1;
    idx%=TIMER_LOG_MAX_LEN;
    return log[idx];
  }
  bool empty(){
    return cnt == 0;
  }
  void init(){
    // INFO(NCCL_INIT, "struct timer_log_res = %d", sizeof(struct timer_log_res));
    // INFO(NCCL_INIT, "uint8_t = %d", sizeof(uint8_t));
    // INFO(NCCL_INIT, "unsigned long long = %d", sizeof(unsigned long long));
    // INFO(NCCL_INIT, "int = %d", sizeof(int));
    // INFO(NCCL_INIT, "double = %d", sizeof(double));
    // INFO(NCCL_INIT, "srcIp = %d", (long long)&t_res[0].srcIp - (long long)t_res);
    // INFO(NCCL_INIT, "dscIp = %d", (long long)&t_res[0].dscIp - (long long)t_res);
    // INFO(NCCL_INIT, "send_start_sec = %d", (long long)&t_res[0].send_start_sec - (long long)t_res);
    // INFO(NCCL_INIT, "send_end_sec = %d", (long long)&t_res[0].send_end_sec - (long long)t_res);
    // INFO(NCCL_INIT, "diff = %d", (long long)&t_res[0].diff - (long long)t_res);
    // INFO(NCCL_INIT, "size = %d", (long long)&t_res[0].size - (long long)t_res);
    // INFO(NCCL_INIT, "rate = %d", (long long)&t_res[0].rate - (long long)t_res);


    cnt = 0;
    idx = 0;
    state = 0;
    stop = 0;
    collect = 0;
    pthread_mutex_init(&lock, NULL);
  }
  bool setState(int to){
    // return 1;

    if(state != 0) return 0;
    if(pthread_mutex_trylock(&lock) == 0){
      if(state == 0) state = to;
      pthread_mutex_unlock(&lock);
      return state == to;
    }
    return 0;
  } 
  void freeState(){
    // pthread_mutex_lock(&lock);
    state = 0;
    // pthread_mutex_unlock(&lock);
  }
  void destroy(){
    pthread_mutex_destroy(&lock);
  }
};

#ifdef NET_IB_CC
struct timer_log_queue global_timer_log;
#else
extern struct timer_log_queue global_timer_log;
#endif

#define SOCK_PATH "/tmp/unix_sock"
void* timerLogService(void *args);
void printLogInfo(struct timer_log log);


/*diff net_ib.cc:
 *#define NET_IB_CC
 *#include "timer_log.h"
 *proxy.cc:
 *pthread_create(&global_timer_log.thread, NULL, timerLogService, NULL);
 */

#endif